﻿using Shop.Model.DB;
using Shop.Model.Spec;
using Shop.Model.SpecGroup;
using Shop.RemoteModel.GoodsSpec.Model;
using Shop.Repository;
using SqlSugar;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;

namespace Shop.Collect.lmpl
{
    internal class SpecGroupCollect : ISpecGroupCollect
    {
        private readonly ISpecGroupRepository _Repository;
        private readonly IGoodsSpecRepository _Spec;
        public SpecGroupCollect (ISpecGroupRepository repository, IGoodsSpecRepository spec)
        {
            this._Spec = spec;
            this._Repository = repository;
        }
        public SpecDto[] GetSpec (long[] specId)
        {
            return this._Spec.GetsSpec(specId);
        }
        public Dictionary<long, int> SetSpecSort (DBGoodsSpec spec, int sort)
        {
            int num = spec.Sort - sort;
            Dictionary<long, int> sorts = new Dictionary<long, int>()
            {
               {spec.Id,sort }
            };
            if (Math.Abs(num) == 1)
            {
                long id = this._Spec.Get(a => a.GroupId == spec.GroupId && a.Sort == sort, a => a.Id);
                if (id != 0)
                {
                    sorts.Add(id, spec.Sort);
                }
            }
            else
            {
                int begin = spec.Sort;
                int end = sort;
                if (begin > end)
                {
                    begin = sort;
                    end = spec.Sort - 1;
                }
                else
                {
                    begin += 1;
                }
                var datas = this._Spec.Gets(a => a.GroupId == spec.GroupId && SqlFunc.Between(a.Sort, begin, end), a => new
                {
                    a.Id,
                    a.Sort
                });
                if (!datas.IsNull())
                {
                    num = num > 0 ? 1 : -1;
                    datas.ForEach(c =>
                    {
                        sorts.Add(c.Id, c.Sort + num);
                    });
                }
            }
            this._Spec.SetSort(sorts);
            return sorts;
        }
        public Dictionary<long, int> SetGroupSort (DBGoodsSpecGroup group, int sort)
        {
            int num = group.Sort - sort;
            Dictionary<long, int> sorts = new Dictionary<long, int>()
            {
               {group.Id,sort }
            };
            if (Math.Abs(num) == 1)
            {
                long id = this._Repository.Get(a => a.GoodsId == group.GoodsId && a.Sort == sort, a => a.Id);
                if (id != 0)
                {
                    sorts.Add(id, group.Sort);
                }
            }
            else
            {
                int begin = group.Sort;
                int end = sort;
                if (begin > end)
                {
                    begin = sort;
                    end = group.Sort - 1;
                }
                else
                {
                    begin += 1;
                }
                var datas = this._Repository.Gets(a => a.GoodsId == group.GoodsId && SqlFunc.Between(a.Sort, begin, end), a => new
                {
                    a.Id,
                    a.Sort
                }).OrderBy(c => c.Sort).ToArray();
                if (!datas.IsNull() && datas[0].Sort == sort)
                {
                    num = num > 0 ? 1 : -1;
                    for (int i = 0; i < datas.Length; i++)
                    {
                        int next = i + 1;
                        var t = datas[i];
                        int s = t.Sort + num;
                        sorts.Add(t.Id, s);
                        if (next != datas.Length && datas[next].Sort != s)
                        {
                            break;
                        }
                    }
                }
            }
            this._Repository.SetSort(sorts);
            return sorts;
        }
        public GoodsSpecGroup[] Gets (long goodsId)
        {
            SpecGroupDto[] groups = this._Repository.Gets(goodsId);
            if (groups.IsNull())
            {
                return null;
            }
            GoodsSpecDto[] spec = this._Spec.Gets(goodsId);
            return groups.ConvertAll(a => new GoodsSpecGroup
            {
                Id = a.Id,
                GroupName = a.GroupName,
                Sort = a.Sort,
                Spec = spec.Convert(c => c.GroupId == a.Id, c => new GoodsSpec
                {
                    Id = c.Id,
                    SpecIcon = c.SpecIcon,
                    SpecName = c.SpecName,
                    Sort = c.Sort
                })
            });
        }
        public GoodsSpecGroup[] Sync (long goodsId, SpecGroup[] groups)
        {
            return this._Repository.Sync(goodsId, groups);
        }

        public void DeleteSpec (long[] specId)
        {
            this._Spec.Delete(specId);
        }
        public void DeleteSpec (DBGoodsSpec spec)
        {
            this._Spec.Delete(spec.Id);
        }

        public DBGoodsSpec GetSpec (long specId)
        {
            return this._Spec.Get(specId);
        }
        public void CheckIsRepeart (long groupId, string name)
        {
            if (this._Spec.IsExist(c => c.GroupId == groupId && c.SpecName == name))
            {
                throw new ErrorException("shop.goods.spec.name.repeat");
            }
        }
        public long AddSpec (GoodsSpecAddDto data)
        {
            this.CheckIsRepeart(data.GroupId, data.SpecName);
            data.Sort = this._Spec.Max(c => c.GroupId == data.GroupId, c => c.Sort) + 1;
            return this._Spec.Add(data);

        }
        public bool SetSpec (DBGoodsSpec spec, GoodsSpecSetDto set)
        {
            if (set.SpecName != spec.SpecName)
            {
                this.CheckIsRepeart(spec.GroupId, set.SpecName);
            }
            return this._Spec.Update(spec, set);

        }

        public long AddGroup (SpecGroupAdd datum)
        {
            if (this._Repository.IsExist(c => c.GoodsId == datum.GoodsId && c.GroupName == datum.GroupName))
            {
                throw new ErrorException("shop.spec.group.name.repeat");
            }
            SpecGroupAddDto add = datum.ConvertMap<SpecGroupAdd, SpecGroupAddDto>();
            add.Sort = this._Repository.Max(c => c.GoodsId == datum.GoodsId, c => c.Sort) + 1;
            return this._Repository.Add(add);
        }

        public DBGoodsSpecGroup GetGroup (long id)
        {
            return this._Repository.Get(id);
        }

        public void DeleteGroup (DBGoodsSpecGroup group)
        {
            long[] specId = this._Spec.Gets<long>(a => a.GroupId == group.Id, c => c.Id);
            if (specId.IsNull())
            {
                this._Repository.Delete(group.Id);
                return;
            }
            this._Repository.Delete(group.Id, specId);
        }

        public bool SetGroup (DBGoodsSpecGroup group, string name)
        {
            if (group.GroupName == name)
            {
                return false;
            }
            else if (this._Repository.IsExist(c => c.GoodsId == group.GoodsId && c.GroupName == name))
            {
                throw new ErrorException("shop.spec.group.name.repeat");
            }
            this._Repository.SetName(group.Id, name);
            return true;
        }
    }
}
